#include "common.h"


int main(int argc, char *argv[])
{
	int sockfd, portno;
	struct sockaddr_in dest;
	char buffer[MAXBUF];
	char buffer_pad[MAXBUF];
	char buffer2[MAXBUF];
	char* client_dest;
	char fbuf[MAXBUF];
	fd_set readfds, active_fd_set;
	size_t bytes_read;
	const char delimiters[] = ":";

	/* Make sure we have the right number of parameters */
	if (argc < 3) {
		fprintf(stderr, "usage %s hostname port\n", argv[0]);
		exit(0);
	}
	portno = atoi(argv[2]);

	/* Create the socket */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd < 0)
	{
		perror("ERROR opening socket");
		exit(1);
	}

	/* Initialize server address/port struct */
	memset(&dest, 0, sizeof(dest));
	dest.sin_family      = AF_INET;
	dest.sin_addr.s_addr = htonl(INADDR_ANY);
	dest.sin_port        = htons(portno);

	/* Connect to server */
	if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) < 0)
	{
		perror("ERROR on connecting");
		exit(1);
	}
	FD_ZERO (&active_fd_set);
	FD_SET(STDIN_FILENO, &active_fd_set);
	FD_SET (sockfd, &active_fd_set);

	printf("Enter message\n");

	memset(buffer,'\0',sizeof(buffer));
	memset(buffer_pad,'\0',sizeof(buffer_pad));
	memset(buffer2,'\0',sizeof(buffer2));
	// Read on commande line a first message
	if( Readline(STDIN_FILENO, buffer, MAXBUF-1) < 0)
	{
		puts("Read failed");
		return 1;
	}

	char client_adv[] = "001\n";
	// Notify the server that messages coming from this socket are clients messages
	if( Sendline(sockfd, client_adv, strlen(client_adv)) < 0) {
		puts("Send failed");
		return 1;
	}
	if( Readline(sockfd, buffer, MAXBUF-1) < 0) // Read : What is your nickname ?
	{
		puts("Read failed");
		return 1;
	}
	printf("%s", buffer); // Display : What is your nickname ?

	while (1){

		memset(buffer,'\0',sizeof(buffer));
		memset(buffer2,'\0',sizeof(buffer));
		memset(buffer_pad,'\0',sizeof(buffer_pad));

		readfds = active_fd_set;
		/* select() on STDIN_FILENO and server's socket */
		if(select(sockfd+1,&readfds,NULL,NULL,NULL) == -1){
			perror("Erreur lors de l'appel a select -> ");
			exit(1);
		}
		// if data is entered on STDIN_FILENO
		if(FD_ISSET(STDIN_FILENO, &readfds)){
			if( Readline(STDIN_FILENO, buffer, MAXBUF-1) < 0)
			{
				puts("Read failed");
				break;
			}
			// Send data to server with header "001"
			sprintf(buffer_pad,"001%s", buffer);
			if( Sendline(sockfd, buffer_pad, strlen(buffer_pad)) < 0) {
				puts("Send failed");
				return 1;
			}
		}

		// if data is entered on STDIN_FILENO
		if(FD_ISSET(sockfd, &readfds)){
			if( Readline(sockfd, buffer2, MAXBUF-1) < 0)
			{
				puts("Read failed");
				break;
			}
			printf("%s", buffer2);
			fflush(stdout);

			/* If the header of the buffer of server's socket is "-fs":
			 *  a socket is created to accept() connection from the
			 *  other client */
			if (buffer2[0] == '-' && buffer2[1] == 'f' && buffer2[2] == 's'
					&& buffer2[3] != '2' ){
				client_dest = &(buffer2[4]);

				char *token;

				token = strtok (client_dest, delimiters);
				printf("Ready to receive a file\n");
				// Initialize a TCP listening socket.
				int sock_serv; // listening socket
				struct sockaddr_in servaddr; // socket address struct
				int tr = 1;

				if ( (sock_serv = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
					fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
					exit(EXIT_FAILURE);
				}

				/*Set all bytes in socket address structure to zero,
				    and fill in the relevant data members */

				memset(&servaddr, 0, sizeof(servaddr));
				servaddr.sin_family      = AF_INET;
				servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
				servaddr.sin_port        = htons(0);

				/* Bind our socket addresss to the listening socket,
				     and call listen()*/

				if (setsockopt(sock_serv,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int)) == -1) {
					perror("setsockopt");
					exit(1);
				}
				if ( bind(sock_serv, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
					fprintf(stderr, "ECHOSERV: Error calling bind()\n");
					exit(EXIT_FAILURE);
				}

				if ( listen(sock_serv, BACKLOG) < 0 ) {
					fprintf(stderr, "ECHOSERV: Error calling listen()\n");
					exit(EXIT_FAILURE);
				}

				printf("Attente de connexion\n");
				fflush(stdout);
				int addrlen;
				struct sockaddr_in serv_addr2;
				addrlen = sizeof(serv_addr2);

				getsockname(sock_serv, (struct sockaddr *) &serv_addr2, (socklen_t *) &addrlen);

				int new_port = (int) ntohs (serv_addr2.sin_port);
				char* new_ip =  inet_ntoa (serv_addr2.sin_addr);
				sprintf(buffer, "-fs2 %s:%d\n",new_ip, new_port); // send IP:PORT
				sprintf(buffer_pad,"001%s", buffer); // add "001" header
				// send "001-fs2 IP:PORT"
				if( Sendline(sockfd, buffer_pad, strlen(buffer_pad)) < 0) {
					puts("Send failed");
					return 1;
				}
				int sock_clt_fd;
				int size = sizeof(serv_addr2);
				while(1){
					/* accept connection from sender */
					sock_clt_fd = accept (sock_serv, (struct sockaddr *) &serv_addr2,
							(socklen_t *) &size);
					if (sock_clt_fd < 0)
					{
						perror ("accept");
						exit (EXIT_FAILURE);
					}
					fprintf (stderr,"Server: connect from host %s, port %d.\n",
							inet_ntoa(serv_addr2.sin_addr),
							(int) ntohs (serv_addr2.sin_port));

					/* Receiving the file */
					FILE* fp2 ;
					fp2 = fopen(FILENAME2, "wb");
					int compteur2 = 0;

					rewind(fp2);
					int i = 0;
					while (1) {
						// read data from the socket
						i = read(sock_clt_fd , buffer2, MAXBUF);
						// write data to a file
						fwrite(buffer2 , 1 , sizeof(buffer2) , fp2);
						compteur2++;
						printf("Written: %d compteur :%d\n", i, compteur2);
						if ( i == 0 ){ // if there is no more data to read
							// break from while(1) and close the socket
							close(sock_clt_fd);
							break;
						}
					}
					break;
				}
			}

			/* If the header of the buffer of server's socket is "-fs2":
			 *  the client connects to the other client using IP:PORT */
			if (buffer2[0] == '-' && buffer2[1] == 'f' && buffer2[2] == 's'
					&& buffer2[3] == '2' ){
				printf("Parameters to use to connect() and send the file:\n");

				char *ip, *cp, *port;
				cp = &buffer2[5];
				ip = strtok (cp, delimiters); // get the IP
				printf("IP:%s\n", ip);
				port = strtok (NULL, delimiters); // get the PORT
				printf("Port:%s\n", port);

				struct sockaddr_in sa;
				memset(&sa, 0, sizeof(sa));
				sa.sin_family      = AF_INET;
				inet_pton(sa.sin_family, ip, &(sa.sin_addr));
				sa.sin_port        = htons(atoi(port));
				int sock_clt;
				// Create a socket
				if ( (sock_clt = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
					fprintf(stderr, "ECHOSERV: Error creating sending socket.\n");
					exit(EXIT_FAILURE);
				}
				// Connect to the other client
				if (connect(sock_clt, (struct sockaddr *) &sa, sizeof(sa)) < 0)
				{
					perror("ERROR on connecting");
					exit(1);
				}

				/* Sending the file */
				FILE *fp;
				unsigned long fsize;
				// open the file to send
				fp = fopen(FILENAME, "rb");
				if (fp == NULL)
				{
					printf("File not found!\n");
					return 1;
				}
				else
				{
					printf("Found file %s\n", FILENAME);

					fseek(fp, 0, SEEK_END);
					fsize = ftell(fp); // total size of the file
					rewind(fp);

					printf("File contains %ld bytes!\n", fsize);
					printf("Sending the file now\n");
				}
				bytes_read = 0;
				int compteur =0;
				while(1) {
					// Read data from the file
					bytes_read = fread(fbuf, sizeof(char), sizeof(fbuf), fp);

					if (bytes_read < 0) {
						perror("fread");
					}
					// Write data in the socket
					write(sock_clt, fbuf, bytes_read);
					compteur++;
					printf("Sent: %lu compteur: %d\n", bytes_read, compteur);
					if (bytes_read == 0){
						close(sock_clt);
						break;
					}
				}
				fclose(fp);
			}

		}
	}
	close(sockfd);

	return 0;
}
